﻿ #region Disclaimer/Info
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //
 //   File:		Combiner.cs
 //   Website:		http://dexterblogengine.com/
 //   Authors:		http://dexterblogengine.com/About.ashx
 //   Rev:		1
 //   Created:		19/01/2011
 //   Last edit:		19/01/2011
 //   License:		GNU Library General Public License (LGPL)
 // 
 //   For updated news and information please visit http://dexterblogengine.com/
 //   Dexter is hosted to Codeplex at http://dexterblogengine.codeplex.com
 //   For any question contact info@dexterblogengine.com
 //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 #endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Dexter.Caching;
using Dexter.CallContext;
using Dexter.Core.Keys;
using Dexter.Domain.Model;
using Dexter.Logger.Contracts;
using Dexter.Services;

namespace Dexter.Web.Mvc.ResourceCombiner {
	public class Combiner : ICombiner {
		readonly ICacheProvider cacheService;
		readonly SiteConfiguration configuration;
		readonly HttpContextBase contex;
		readonly IBlogTheme currentTheme;
		readonly HashSet <string> javascriptResources;
		readonly IKeyBuilder keyBuilder;
		readonly ILogger logger;
		readonly HashSet <string> stylesheetResources;
		readonly IThemeManager themeManager;
		readonly IUrlBuilderBase urlBuilderBase;

		/// <summary>
		/// 	Initializes a new instance of the <see cref = "Combiner" /> class.
		/// </summary>
		/// <param name = "logger">The logger.</param>
		/// <param name = "cacheService">The cache service.</param>
		/// <param name = "themeManager">The theme manager.</param>
		/// <param name = "contex">The contex.</param>
		/// <param name = "configurationService">The configuration service.</param>
		/// <param name = "keyBuilder">The key builder.</param>
		/// <param name = "urlBuilderBase">The URL builder base.</param>
		public Combiner ( ILogger logger, ICacheProvider cacheService, IThemeManager themeManager, IDexterContext contex, IConfigurationService configurationService, IKeyBuilder keyBuilder, IUrlBuilderBase urlBuilderBase ) {
			this.logger = logger;
			this.cacheService = cacheService;
			this.themeManager = themeManager;
			this.contex = contex.Context;
			this.keyBuilder = keyBuilder;
			this.urlBuilderBase = urlBuilderBase;
			this.javascriptResources = new HashSet <string> ( );
			this.stylesheetResources = new HashSet <string> ( );
			this.configuration = configurationService.Configuration;
			this.currentTheme = this.themeManager.GetThemeByName ( configuration.ThemeName );
		}

		#region ICombiner Members

		/// <summary>
		/// 	Clears all resourse added.
		/// </summary>
		public void Clear ( ) {
			javascriptResources.Clear ( );
			stylesheetResources.Clear ( );
		}

		/// <summary>
		/// 	Clears all javascript resource added.
		/// </summary>
		public void ClearAllJavascriptResource ( ) {
			javascriptResources.Clear ( );
		}

		/// <summary>
		/// 	Clears all stylesheet resource added.
		/// </summary>
		public void ClearAllStylesheetResource ( ) {
			stylesheetResources.Clear ( );
		}

		/// <summary>
		/// 	Adds the specified stylesheet to the combiner manager.
		/// </summary>
		/// <param name = "resource">The resource.</param>
		/// <exception cref = "ArgumentNullException"> If <paramref name = "resource" /> is <c>null</c> .</exception>
		public void AddStylesheet ( string resource ) {
			if (resource == null)
				throw new ArgumentNullException ( "resource", "Invalid resource." );

			stylesheetResources.Add ( resource );
		}

		/// <summary>
		/// 	Adds the specified javascript to the combiner manager.
		/// </summary>
		/// <param name = "resource">The resource.</param>
		/// <exception cref = "ArgumentNullException"> If <paramref name = "resource" /> is <c>null</c>.</exception>
		public void AddJavascript ( string resource ) {
			if (resource == null)
				throw new ArgumentNullException ( "resource", "Invalid resource." );

			javascriptResources.Add ( resource );
		}

		///<summary>
		///	Adds the specified stylesheets to the combiner manager.
		///</summary>
		///<param name = "resources">The source.</param>
		///<exception cref = "ArgumentNullException"> If <paramref name = "resources" /> is <c>null</c>.</exception>
		public void AddStylesheets ( IEnumerable <string> resources ) {

			if(resources == null)
				throw new ArgumentNullException ( "resources","Invalid resources." );

			resources.ForEach ( this.AddStylesheet );
		}

		///<summary>
		///	Adds the specified javascripts to the combiner manager.
		///</summary>
		///<param name = "resources">The source.</param>
		///<exception cref = "ArgumentNullException"> If <paramref name = "resources" /> is <c>null</c>.</exception>
		public void AddJavascripts ( IEnumerable <string> resources ) {
			if (resources == null)
				throw new ArgumentNullException ( "resources", "Invalid resources." );

			resources.ForEach ( this.AddJavascript );
		}

		/// <summary>
		/// 	Renders all stylesheets not combined
		/// </summary>
		/// <example>
		/// 	<![CDATA[
		/// &lt;link type="text/css" rel="stylesheet" href="/site.css" /&gt;
		/// &lt;link type="text/css" rel="stylesheet" href="/site2.css" /&gt;
		/// ]]>
		/// </example>
		public string RenderCssFiles ( ) {
			StringBuilder sb = new StringBuilder ( );
			foreach ( var resource in stylesheetResources ) {
				sb.AppendFormat ( "<link type=\"text/css\" rel=\"stylesheet\" href=\"/{0}\" />" , currentTheme.GetStyleUrl ( resource ) );
			}

			return sb.ToString ( );
		}

		/// <summary>
		/// 	Renders all javascripts not combined
		/// </summary>
		/// <example>
		/// 	<![CDATA[
		/// &lt;script src="jquery-1.4.2.min.js" type="text/javascript" language="javascript"/&gt;&lt;/script/&gt;
		/// &lt;script src="effects.js" type="text/javascript" language="javascript"/&gt;&lt;/script/&gt;
		/// ]]>
		/// </example>
		public string RenderJsFiles ( ) {
			StringBuilder sb = new StringBuilder ( );
			foreach ( var resource in javascriptResources ) {
				sb.AppendFormat ( "<script src=\"{0}\" type=\"text/javascript\" language=\"javascript\"></script>" , currentTheme.GetScriptUrl ( resource ) );
			}

			return sb.ToString ( );
		}

		/// <summary>
		/// 	Renders only one link to the combined resource
		/// </summary>
		/// <example>
		/// 	<![CDATA[
		/// &lt;link type="text/css" rel="stylesheet" href="/combines/css/123456" /&gt;
		/// ]]>
		/// </example>
		public string RenderCssCombined ( ) {
			var key = keyBuilder.Create ( stylesheetResources );

			if (cacheService.Get ( key ) == null)
				cacheService.Add ( key , stylesheetResources , TimeSpan.FromDays ( 7 ) );

			return string.Format ( "<link type=\"text/css\" rel=\"stylesheet\" href=\"{0}\" />" , urlBuilderBase.StylesheedCombinedUrl ( key ) );
		}

		/// <summary>
		/// 	Renders only one link to the combined resource
		/// </summary>
		/// <example>
		/// 	<![CDATA[
		/// &lt;script src="combines/js/123456" type="text/javascript" language="javascript"/&gt;&lt;/script/&gt;
		/// ]]>
		/// </example>
		public string RenderJsCombined ( ) {
			var key = keyBuilder.Create ( javascriptResources );
			
			if (cacheService.Get ( key ) == null)
				cacheService.Add ( key, javascriptResources, TimeSpan.FromDays ( 7 ) );
			
			return string.Format ( "<script type=\"text/javascript\" src=\"{0}\" ></script>", urlBuilderBase.JavascriptCombinedUrl ( key ) );
		}

		#endregion
	}
}
